Terraform初心者が実戦投入するまでにやったこと
Terraformとは
HashiCorp社が提供するインフラ構成管理ツールです。
HCL(HashiCorp Configuration Language)という⾔語で .tf
拡張子のファイルにインフラ構成を記述し、Terraformのコマンドでそのファイルを実行するとその構成通りのインフラが作成されます。
いわゆるInfrastructure as Codeが実現できるので、インフラ構築において以下のようなことが可能になります。
- Gitなどのバージョン管理システムで変更履歴を管理する
- コードレビュー
- インフラ構成の横展開(再利用)が容易になる
- コンソールで作業することによる人為的ミスを防ぐことができる
またTerraformはAWS専用のツールというわけでなく、GCPやDockerなど他のインフラにも幅広く対応しています。
やったこと(時系列)
とりあえずさわって見る
まずはTerraformでインフラ構築するとはどういうことか、感覚をつかむため適当にさわってみました。
主に以下のQiitaを参考にしました。(公式ドキュメントを見るのが一番良いと思いましたが、英語だったので敬遠してしまいました。。)
この時点で
- へー、EC2インスタンス作成する際にVPCを指定しないとデフォルトVPCになるのかー
- へー、指定しなかったらキーペアも作成されないのかー
くらいのレベル感です。
Terraform面白そう!と俄然興味が湧きました。
Tipsを学ぶ
なんとなく .tf
ファイルを書いて、 terraform plan
terraform apply
してファイル修正〜みたいな流れが掴めたところで、以下記事を読んでより深い部分の知見を学びました。
Terraform職人入門: 日々の運用で学んだ知見を淡々とまとめる
複数環境に対応する方法を学ぶ
今回構築予定だったインフラには3環境あり、それぞれAWSアカウントが異なりました。
- ローカル:自分のAWSアカウント。ここで色々検証構築する
- ステージング:お客様AWSアカウントA
- 本番:お客様AWSアカウントB
こういった複数アカウント間を行き来する方法みんなどうやってるのかなーと気になったので社内で聞いてみたところ、以下の記事でdirenvをおすすめされました。(実は前述のQiita記事でもdirenv紹介されていました)
ディレクトリ移動だけでアカウントが切り替わってとても便利です!
参考書を読む
このあたりで、「TerraformでAWS環境構築する際の良い技術書が発売されたらしいぞ!」という情報を聞きつけ、即買いしました。
「Pragmatic Terraform on AWS」です。書評については以下エントリが詳しいのでこちらをご覧ください。
わかりやすくてサクサク読めました。直近使う予定のなかったサービスの章を省略したりしましたが、おそらく2時間くらいで読了しました。
それでいて最初の一歩からベストプラクティスやモジュール設計原則など実践的な知見も盛り込まれていて大満足です!
Gitで管理する
そろそろコードを書き始めます。書き始めるにあたりちゃんとGitリポジトリを作って変更履歴を管理するようにしました。
ぶっちゃけ今回の案件はインフラ構築するのは私一人だったので、コードレビューもありませんでしたしGitを使う必要性は薄かったです。が、過去の自分がやったことを覚えている自信がないのと、将来的に他の人が参考にすることもあるかもしれないと思いGitを使うことにしました。
実戦開始
実践開始です。ディレクトリ構成は以下のような形になりました。
. ├── environment │ ├── local-pjxxx │ │ ├── .envrc │ │ ├── README.md │ │ ├── alb │ │ │ ├── main.tf │ │ │ ├── output.tf │ │ │ └── variables.tf │ │ ├── ec2 │ │ │ ├── main.tf │ │ │ ├── output.tf │ │ │ └── variables.tf │ │ ├── security_group │ │ │ ├── main.tf │ │ │ ├── output.tf │ │ │ └── variables.tf │ │ ├── その他のリソース │ │ ├── ・ │ │ └── ・ │ ├── production-pjxxx │ │ ├── ・ │ │ └── ・ │ └── staging-pjxxx │ ├── ・ │ └── ・ └── modules ├── alb │ ├── main.tf │ ├── output.tf │ └── variables.tf ├── ec2 │ ├── main.tf │ ├── output.tf │ ├── userdata.txt │ └── variables.tf ├── security_group │ ├── main.tf │ ├── output.tf │ └── variables.tf ├── その他のリソース ├── ・ └── ・
terraform apply
などを行なうディレクトリはenvironment/local-pjxxx/alb
などです。- 具体的なコードはmodule以下に書きます。それをenvironment下のファイルから呼び出します。
例えばenvironment/local-pjxxx/alb
のmain.tf
で../../../modules/alb
を呼びます。環境ごとにパラメーターが変わる部分はモジュール内で変数化しておき、呼び出す際に値を指定するようにします。
今回はサービスごとにStateを分ける構成にしました。そうすることで各種terraform
コマンドの処理時間短縮化や、操作ミス時の影響範囲の縮小化ができたと思っています。
しかし一方で、Stateをまたいで値を参照する必要が生じる場合があってその辺りはちょっと面倒でした。例えばSecurity Groupを作成するのと、それをEC2にアタッチするのは別Stateにしていたのですが、そうすると前述のQiitaのStateを跨いで値を参照する項であるように output
や terraform_remote_state
の記述がモリモリ増えるのが煩雑だったなと感じています。この点はプロジェクト規模によって使い分けていきたいですね。
実戦時に参考にしていた情報
とにかく以下の情報をめちゃめちゃ参考にしていました。この辺りのいずれかに転がっているサンプルコードをコピペしてきて、今回の要件に沿った記述に修正していくというのが主な作業でした。
- 「Pragmatic Terraform on AWS」とそのGitHubリポジトリ
- 公式サイトAWS Provider
- 公式サイトBuilt-in Functions
- Terraform Module Registry
→公式の公開モジュール群です。公開モジュールをそのまま使うことは今回しませんでしたが、各リソースの記述例として大いに参考にしました。
実戦時に心がけたこと
どこまでTerraformでコード化するのか、という点です。
今回のプロジェクトの要件には「Terraformでコード化する」という部分は含まれていませんでした。ですので別にコンソールで構築しても良かったのです。
そんな中でTerraform採用に至ったモチベーションとしては以下2点です。
- お客様アカウントには既存のリソースがたくさん稼働していて、コンソールで作業した場合の操作ミスが怖かった
- タイトな納期で2環境(ステージング、本番)作る必要があった
ぶっちゃけ1環境つくるだけであればコンソールで手作業したほうが早いです。ですので最初のステージング環境の構築においては、既存リソースが無かった、つまりコンソールで作業した場合の操作ミスのリスクが低いCloudFrontなどは納期に間に合わせるためコンソールで構築することにしました。そういったリソースに関しては後日 terraform import
で改めてコード化し、本番環境はTerraformで構築完了できるようにしたものもあります。
コード化することがゴールではなく、コード化することによってもたらされるメリット/デメリットを考えて使うことが大事だと感じました。
まとめ
私がTerraformを実戦投入するまでにやったことをまとめました。特にdirenvを使って複数環境に対応するのと、「Pragmatic Terraform on AWS」はとてもよかったと思います。オススメです。